package org.test4j.mock.processor.filer;

import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static java.lang.reflect.Modifier.*;
import static org.test4j.mock.faking.util.TypeDesc.T_Object;
import static org.test4j.mock.faking.util.TypeUtility.descriptor;

public class ExecutableHelper {

    public static int getAccess(ExecutableElement executable) {
        Set<Modifier> modifiers = executable.getModifiers();
        int access = 0;
        for (Modifier modifier : modifiers) {
            String value = modifier.name();
            if ("ABSTRACT".equals(value)) {
                access += ABSTRACT;
            } else if ("NATIVE".equals(value)) {
                access += NATIVE;
            } else if ("STATIC".equals(value)) {
                access += STATIC;
            }
        }
        return access;
    }

    public static String getParaDesc(ExecutableElement executable, Map<String, String> classVars) {
        StringBuilder buff = new StringBuilder("(");
        Map<String, String> varMaps = getVarDesc(executable.getTypeParameters(), new HashMap<>(classVars));
        List<? extends VariableElement> paras = executable.getParameters();
        for (VariableElement para : paras) {
            buff.append(descriptor(para.asType().toString(), varMaps));
        }
        TypeMirror returnType = executable.getReturnType();
        buff.append(")").append(descriptor(returnType.toString(), varMaps));
        return buff.toString();
    }

    public static Map<String, String> getVarDesc(List<? extends TypeParameterElement> varTypes, Map<String, String> varMaps) {
        for (TypeParameterElement varType : varTypes) {
            String varName = varType.getSimpleName().toString();
            List<? extends TypeMirror> bounds = varType.getBounds();
            if (bounds == null || bounds.isEmpty()) {
                varMaps.put(varName, T_Object.DESC);
            } else {
                varMaps.put(varName, descriptor(bounds.get(0).toString(), varMaps));
            }
        }
        return varMaps;
    }
}